/*
 * @Author       : Zhao Lvhua zhaolh@linkcharging.com
 * @Date         : 2024-09-02 01:04:00
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-15 13:02:44
 * @FilePath     : \openchaoji-corelib\shared\src\OpenChaoJi_utility_transport_gbt27930_b_recv.c
 * @Description  :
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include "OpenChaoJi_utility_transport_gbt27930_b.h"
#include "OpenChaoJi_utility_transport_gbt27930_b_private.h"

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)

extern bool s_transport_debug_enable;


/*
* @brief: 对于底层接收到的数据帧进行缓存，并且检测判断CAN接收消息帧类型，长度等是否满足格式要求
* @param {can_pdu *} pdu 接收到数据帧
* @return {*}不可靠消息数据帧返回0，可靠消息数据帧返回 1，错误返回-1
*/
int16_t OpenChaoJi_transport_gbt27930_b_put_canframe_in_cache(struct can_pdu * pdu, struct OpenChaoJi_gbt27930_b_canframe_cache * frame_cache)
{
	uint8_t pf = pdu->can_id.bit.pf;
	uint8_t priority = pdu->can_id.bit.p;
	uint8_t dp = pdu->can_id.bit.dp;
	uint8_t edp = pdu->can_id.bit.edp;
	uint8_t dlc = pdu->can_dlc;

	if (frame_cache == NULL){
		LOG_CRIT("transportrecv frame_cache is null");
		return -1;
	}

	if (frame_cache->cnt >= (sizeof(frame_cache->pdu)/sizeof(*(frame_cache->pdu))))
	{
		//error 缓存队列满
		LOG_ERR("transportrecv frame_cache is full");
		return -1;

	}
	frame_cache->pdu[frame_cache->cnt] = *pdu;
	frame_cache->cnt++;

	if(pf == PF_URSMIF)//SM_URM
    {
    	if (priority != 6 || dp != 0 || edp != 0){
    		//error 不可靠消息帧的帧格式错误
    		LOG_ERR("transportrecv usm frame type is error");
        	return -1;
    	}
		else if (dlc != 8){
			//error 不可靠消息帧的数据长度错误
			LOG_ERR("transportrecv usm frame length is error");
			return -1;
		}
		else {
			//不可靠息信
			return 0;
		}
    }
	else if (pf == PF_LMIF)
	{
		if (priority != 6 || dp != 0 || edp != 0){
    		//error 可靠长消息帧的帧格式错误
    		LOG_ERR("transportrecv lsm data frame type is error");
        	return -1;
    	}
		else if (dlc != 8){
			//error 可靠长消息帧的数据长度错误
			LOG_ERR("transportrecv lsm data frame length is error");
			return -1;
		}
		else {
			//可靠息信帧
			return 1;
		}
	}
	else if (pf == PF_RSMIF)
	{
		if (priority != 4 || dp != 0 || edp != 0){
    		//error 可靠短消息帧的帧格式错误
    		LOG_ERR("transportrecv lsm frame type is error");
        	return -1;
    	}
		else if (dlc != 8){
			//error 可靠短消息帧的数据长度错误
			LOG_ERR("transportrecv lsm frame length is error");
			return -1;
		}
		else {
			//可靠息信帧
			return 1;
		}
	}
	else if (pf == PF_RMCF)
	{
		if (priority != 3 || dp != 0 || edp != 0){
    		//error 可靠消息控制帧的帧格式错误
    		LOG_ERR("transportrecv lsm ctrl frame type is error");
        	return -1;
    	}
		else if (dlc != 8){
			//error 可靠消息控制帧的数据长度错误
			LOG_ERR("transportrecv lsm ctrl frame length is error");
			return -1;
		}
		else {
			//可靠息信帧
			return 1;
		}
	}
	else
	{
		//error
		if (pf != PF_VER_NEG)
		{
			LOG_ERR("transportrecv pf is't 0x34~0x37, other error");
		}
		return -1;
	}
}

int16_t OpenChaoJi_transport_gbt27930_b_take_canframe_from_cache(struct OpenChaoJi_gbt27930_b_canframe_cache * frame_cache, struct can_pdu * pdu)
{
	// uint8_t cnt = frame_cache->cnt;

	if (frame_cache == NULL){
		//error
		LOG_CRIT("transportrecv frame_cache space is null");
		return -1;
	}

	if (frame_cache->cnt <= 0)
	{
		//缓存空
		//error
		LOG_DEBUG("transportrecv frame_cache is empty");
		return -1;
	}

	*pdu = frame_cache->pdu[frame_cache->cnt-1];	// CYGFIX 取数据cnt应-1
//	LOG_DEBUG("frame_cache->cnt = %d; can_id = %08X",frame_cache->cnt,pdu->can_id.uint32_tWord);
	frame_cache->cnt--;

	return 0;
}


int16_t OpenChaoJi_utility_transport_gbt27930_b_got_urm_msg(struct OpenChaoJi_gbt27930_b_urmcb  * urmcb, struct can_data * recv_data)
{
	if (urmcb == NULL){
		//error
		LOG_CRIT("transportrecv urmcb space is null");
		return -1;
	}

	//不需要确认短消息
    if (urmcb->sm_recved_flag == 1)
    {
        recv_data->data = urmcb->sm_recv_buf;
        recv_data->len = urmcb->sm_recv_len;
        urmcb->sm_recved_flag = 0;
        return 0;
    }

	return -1;
}


/*
* @brief: 获取可靠消息体的消息，如果有消息，则把消息存放到接收数据参数recv_data里面
* @param {OpenChaoJi_gbt27930_b_rmcb  *} rmcb 可靠消息的消息体指针，包含必要的环境信息。
* @param {can_data *} recv_data 用来存储消息数据体
* @return 有新消息(需要使用者释放返回0, 不需要使用者释放的返回1)，没有新消息返回-1。
*/
int16_t OpenChaoJi_utility_transport_gbt27930_b_got_rm_msg(struct OpenChaoJi_gbt27930_b_rmcb  * rmcb, struct can_data * recv_data)
{
	if (rmcb == NULL){
		LOG_CRIT("transportrecv rmcb space is null");
		return -1;
	}

//	LOG_DEBUG("transportrecv rmcb->sm_recved_flag = %d rmcb->lm_recved_flag = %d", rmcb->sm_recved_flag, rmcb->lm_recved_flag);
 	if (rmcb->sm_recved_flag == 1)
    {
    	recv_data->data = OpenChaoJi_os_malloc(rmcb->sm_recv_len);
		if (recv_data->data == NULL){
			LOG_CRIT("transportrecv malloc fail");
			return -1;
		}
    	memcpy(recv_data->data, rmcb->sm_recv_buf, rmcb->sm_recv_len);
        recv_data->len =  rmcb->sm_recv_len;
        rmcb->sm_recved_flag = 0;
        return 0;		// 短消息动态申请的, 需要使用者释放, 返回1
    }

    //可靠长消息
    if (rmcb->lm_recved_flag == 1)
    {
        recv_data->data = rmcb->lm_recv_buf;
        recv_data->len = rmcb->lm_recv_tbytes;
        rmcb->lm_recved_flag = 0;
        return 0;		// 长消息, 动态申请的, 所以需要使用者释放, 返回0
    }
	return -1;
}

int16_t OpenChaoJi_utility_transport_gbt27930_b_service(struct OpenChaoJi_gbt27930_b_rmcb * rmcb)
{
	//需要确认短消息处理
    if (rmcb->sm_send_state != RSM_S0_IDLE)
    {
        OpenChaoJi_transport_gbt27930_b_rsm_send_process(rmcb);
    }

	//需要确认长消息处理
    if (rmcb->lm_send_state != LM_SEND_IDLE)
    {
        OpenChaoJi_transport_gbt27930_b_rlm_send_process(NULL,rmcb);
    }

	if (rmcb->lm_recv_state != LM_RECV_S0_IDLE)
    {
        OpenChaoJi_transport_gbt27930_b_rlm_recv_process(NULL,rmcb);
    }

	return 0;
}


/*
* @brief: 对gbt27930 B类系统接收数据帧进行类型解析，分发处理
* @param {can_pdu *} pdu 接收到数据帧
* @param {OpenChaoJi_context_utility_transport} *context 系统上下文指针，包含必要的环境信息。
* @return {*}成功返回0，失败返回-1。
*/
int16_t OpenChaoJi_transport_gbt27930_b_rm_input(struct can_pdu * pdu, struct OpenChaoJi_gbt27930_b_rmcb * rmcb)
{
	uint8_t pf = pdu->can_id.bit.pf;
    uint8_t ack_type = 0;

    if(pf == PF_LMIF)//LM
    {
        OpenChaoJi_transport_gbt27930_b_rlm_recv_process(pdu, rmcb);
    }
    else if(pf == PF_RSMIF)//SM_RM
    {
        OpenChaoJi_transport_gbt27930_b_rsm_recv_process(pdu, rmcb);
    }
    else if(pf == PF_RMCF)//ACK info
    {
        ack_type = pdu->data[0];
        if(ack_type == SM_ACK)
        {
        	rmcb->rcved_ack_flag = SM_ACK;
            OpenChaoJi_transport_gbt27930_b_rsm_send_process(rmcb);
            rmcb->rcved_ack_flag = RM_INVALID_VALUE;//复位
        }
        else if(ack_type == LM_NACK)
        {
            rmcb->rcved_ack_flag = LM_NACK;
        	OpenChaoJi_transport_gbt27930_b_rlm_recv_process(NULL,rmcb);
			OpenChaoJi_transport_gbt27930_b_rlm_send_process(NULL,rmcb);
            rmcb->rcved_ack_flag = RM_INVALID_VALUE;//复位
        }
		else if(ack_type == LM_EndACK)
        {
            rmcb->rcved_ack_flag = LM_EndACK;
			OpenChaoJi_transport_gbt27930_b_rlm_send_process(NULL,rmcb);
            rmcb->rcved_ack_flag = RM_INVALID_VALUE;//复位
        }
		else if (ack_type == LM_ACK)
		{
			rmcb->rcved_ack_flag = LM_ACK;
			OpenChaoJi_transport_gbt27930_b_rlm_send_process(pdu,rmcb);
            rmcb->rcved_ack_flag = RM_INVALID_VALUE;//复位
		}
        else
        {
            //err
            LOG_ERR("transportrecv 0x37 data[0] is %d is't 0~3, other error", pf);
            return -1;
        }
    }
    else
    {
        //err
        LOG_ERR("transportrecv pf is %d is't 0x34 0x35 0x37, other error", pf);
        return -1;
    }

	return 0;
}

/*
* @brief: gbt27930 B类系统不需要确认短消息的接收处理
* @param {can_pdu *} pdu 接收到数据帧
* @param {OpenChaoJi_context_utility_transport} *context 系统上下文指针，包含必要的环境信息。
* @return {*} 成功返回0，失败返回-1。
*/
int16_t OpenChaoJi_transport_gbt27930_b_urm_input(struct can_pdu * pdu,  struct OpenChaoJi_gbt27930_b_urmcb  * urmcb)
{
	memcpy(urmcb->sm_recv_buf, pdu->data, pdu->can_dlc);
	urmcb->sm_recv_len = pdu->can_dlc;
	urmcb->sm_recved_flag = 1;

	return 0;
}

/*
* @brief: gbt27930 B类系统需要确认短消息的接收处理
* @param {can_pdu *} pdu 接收到数据帧
* @param {OpenChaoJi_context_utility_transport} *context 系统上下文指针，包含必要的环境信息。
* @return {*} 成功返回0，失败返回-1。
*/
int16_t OpenChaoJi_transport_gbt27930_b_rsm_recv_process(struct can_pdu * pdu, struct OpenChaoJi_gbt27930_b_rmcb * rmcb)
{

	memcpy(rmcb->sm_recv_buf, pdu->data, pdu->can_dlc);

	rmcb->sm_recv_len = pdu->can_dlc;
	gbt27930_b_rsm_send_ack(rmcb);
	rmcb->sm_recved_flag = 1;

	return 0;
}

/*
* @brief: gbt27930 B类系统需要确认长消息的接收处理过程
* @param {can_pdu *} pdu 接收到数据帧
* @param {OpenChaoJi_context_utility_transport} *context 系统上下文指针，包含必要的环境信息。
* @return {*} 成功返回0，失败返回-1。
*/
int16_t OpenChaoJi_transport_gbt27930_b_rlm_recv_process(struct can_pdu * pdu, struct OpenChaoJi_gbt27930_b_rmcb * rmcb)
{
	uint8_t fram_idx;

	struct OpenChaoJi_gbt27930_b_rmcb *Msgcb = rmcb;

	switch (Msgcb->lm_recv_state)
	{
		case LM_RECV_S0_IDLE:
			if (pdu != NULL)
			{
				fram_idx = pdu->data[0];
				//接收报文LM(0)
				if(fram_idx == 0)
				{
					//保存lm_tfra,发送LM_ACK(1,k),开启LM_ST2、LMS    _T3, recv_no置零,recv_num置零,recv_tfra置为0.进入S1
		        	Msgcb->lm_tfra = pdu->data[1];
		        	Msgcb->lm_recv_tbytes = (pdu->data[2]|(pdu->data[3]<<8));

					LOG_INFO("transportrecv 0x34 data[0] = 0 lm_tfra = %d lm_recv_tbytes = %d",Msgcb->lm_tfra, Msgcb->lm_recv_tbytes);

					//为长帧信息帧申请内存
			        Msgcb->lm_recv_buf = (uint8_t *)OpenChaoJi_os_malloc(Msgcb->lm_tfra*7);//add redundancy
					if (Msgcb->lm_recv_buf == NULL) {
						//err
						LOG_CRIT("transportrecv lm_recv_buf space malloc is error");
						return -1;
					}

					Msgcb->lm_recv_n = 1;
					Msgcb->lm_recv_k = Msgcb->lm_tfra;
					gbt27930_b_rlm_send_ack(Msgcb);

					Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
					Msgcb->lm_recv_lms_t3_tick = OpenChaoJi_os_get_ticks();
					Msgcb->lm_recv_no = 0;
					Msgcb->lm_recv_num = 0;
					Msgcb->lm_recved_tfra = 0;
					Msgcb->lm_recv_err_cnt = 0;

					Msgcb->lm_recv_state = LM_RECV_S1_DATA_RECEIVING;
				}
			}
			break;

		case LM_RECV_S1_DATA_RECEIVING:
			if (pdu != NULL)
			{
				fram_idx = pdu->data[0];
				//接收报文LM(0)
				if(fram_idx == 0)
				{
					//发 送 LM_ACK(1,k),开启LMS_T2,recv_no置零，recv_num置零，recv_tfra置为0,进入S1
		        	Msgcb->lm_tfra = pdu->data[1];
		        	Msgcb->lm_recv_tbytes = (pdu->data[2]|(pdu->data[3]<<8));

					LOG_INFO("transportrecv 0x34 data[0] = 0 lm_tfra = %d lm_recv_tbytes = %d",Msgcb->lm_tfra, Msgcb->lm_recv_tbytes);

					//为长帧信息帧申请内存
					OPEN_CHAOJI_MEM_FREE_CHECK(Msgcb->lm_recv_buf);
			        Msgcb->lm_recv_buf = (uint8_t *)OpenChaoJi_os_malloc(Msgcb->lm_tfra*7);
					if (Msgcb->lm_recv_buf == NULL) {
						LOG_CRIT("transportrecv lm_recv_buf space malloc is error");
						return -1;
					}

					Msgcb->lm_recv_n = 1;
					Msgcb->lm_recv_k = Msgcb->lm_tfra;
					gbt27930_b_rlm_send_ack(Msgcb);

					Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
					Msgcb->lm_recv_no = 0;
					Msgcb->lm_recv_num = 0;
					Msgcb->lm_recved_tfra = 0;
					Msgcb->lm_recv_err_cnt = 0;


					Msgcb->lm_recv_state = LM_RECV_S1_DATA_RECEIVING;
				}
				else if (fram_idx > 0)
				{
					//长消息已接收完recv_tfra=lm_tfra
					if (Msgcb->lm_recved_tfra == Msgcb->lm_tfra)
					{
						//recv_tfra置为lm_tfra,发送LM_EndofACK . 进 入 S 2
						gbt27930_b_rlm_send_endofack(Msgcb);
						Msgcb->lm_recv_state = LM_RECV_S2_CLOSE_CONN;
						Msgcb->lm_recved_flag = 1;
						LOG_DEBUG("transportrecv recv long frame end Msgcb->lm_recved_tfra = %d", Msgcb->lm_recved_tfra);
					}

					//接收帧序号不连续，漏收报文，n>recv_  no+1且recv_tfra < lm_tfra
					if ((fram_idx > (Msgcb->lm_recv_no + 1)) && (Msgcb->lm_recved_tfra < Msgcb->lm_tfra))
					{
						//发送   LM_ACK(recv_no+1, k),开启 LMS_T2,recv_num置零，保持Sl
						Msgcb->lm_recv_n = Msgcb->lm_recv_no + 1;
						Msgcb->lm_recv_k = Msgcb->lm_tfra - Msgcb->lm_recv_no;
						gbt27930_b_rlm_send_ack(Msgcb);
						Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
						Msgcb->lm_recv_err_cnt = 0;
						Msgcb->lm_recv_num = 0;
						LOG_DEBUG("transportrecv recv long frame lose message fram_idx = %d Msgcb->lm_recv_no = %d \
								Msgcb->lm_recved_tfra = %d Msgcb->lm_tfra = %d",\
								fram_idx, Msgcb->lm_recv_no, Msgcb->lm_recved_tfra, Msgcb->lm_tfra);
					}

					//接收长消息最后一帧，n =  recv_no+1且 recv_tfra+1 = m_tfra
					if ((fram_idx >= (Msgcb->lm_recv_no + 1)) && ((Msgcb->lm_recved_tfra + 1) == Msgcb->lm_tfra))
					{
						//recv_tfra置为 lm_tfra,发送LM_EndofACK,进入S2
						memcpy(&Msgcb->lm_recv_buf[Msgcb->lm_recv_no*7], &pdu->data[1], 7);
						Msgcb->lm_recved_tfra = Msgcb->lm_tfra;
						gbt27930_b_rlm_send_endofack(Msgcb);
						Msgcb->lm_recv_state = LM_RECV_S2_CLOSE_CONN;
						Msgcb->lm_recved_flag = 1;
						LOG_DEBUG("transportrecv recv long frame lose message fram_idx = %d Msgcb->lm_recv_no = %d \
								Msgcb->lm_recved_tfra = %d Msgcb->lm_tfra = %d",\
								fram_idx, Msgcb->lm_recv_no, Msgcb->lm_recved_tfra, Msgcb->lm_tfra);
					}

					//接收当前请求的最后一帧，n=recv   no+ 1且recv_num  ≥ k - 1 且 recv_tfra+1 < lm tfra
					if ((fram_idx > (Msgcb->lm_recv_no + 1))
						&& (Msgcb->lm_recv_num >= (Msgcb->lm_recv_k - 1))
						&& ((Msgcb->lm_recved_tfra + 1) < Msgcb->lm_tfra))
					{
						//recv_no置为 n , 发送LM_ACK(n+1,k),recv_num 置零，recv  _fra加1,LMS T2开启，保持S1
						memcpy(&Msgcb->lm_recv_buf[Msgcb->lm_recv_no*7], &pdu->data[1], 7);
						Msgcb->lm_recv_no = fram_idx;
						Msgcb->lm_recv_n = Msgcb->lm_recv_no + 1;
						Msgcb->lm_recv_k = Msgcb->lm_tfra - Msgcb->lm_recv_no;
						gbt27930_b_rlm_send_ack(Msgcb);
						Msgcb->lm_recv_num = 0;
						++(Msgcb->lm_recved_tfra);
						Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
						Msgcb->lm_recv_err_cnt = 0;
						LOG_DEBUG("transportrecv recv long frame lose message fram_idx = %d Msgcb->lm_recv_no = %d \
								Msgcb->lm_recved_tfra = %d Msgcb->lm_tfra = %d Msgcb->lm_recv_num = %d Msgcb->lm_recv_k = %d",\
								fram_idx, Msgcb->lm_recv_no, Msgcb->lm_recved_tfra, Msgcb->lm_tfra, Msgcb->lm_recv_num, Msgcb->lm_recv_k);
					}

					//未接收完 n =recv_no+1且recv_num<k?1且recv_tfra+1<lm_tfra
					if ((fram_idx == (Msgcb->lm_recv_no + 1))
						&& (Msgcb->lm_recv_num < (Msgcb->lm_recv_k - 1))
						&& ((Msgcb->lm_recved_tfra + 1) < Msgcb->lm_tfra))
					{
						//recv_no置为n,recv  _num加1,recv_tfra 加1,LMS_T2开启，保持S1
						memcpy(&Msgcb->lm_recv_buf[Msgcb->lm_recv_no*7], &pdu->data[1], 7);
						Msgcb->lm_recv_no = fram_idx;
						++Msgcb->lm_recv_num;
						++Msgcb->lm_recved_tfra;
						Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
						Msgcb->lm_recv_err_cnt = 0;
					}
				}
			}

			//接收报文 LM_NACK
			else if (Msgcb->rcved_ack_flag == LM_NACK)
			{
				Msgcb->lm_recv_state = LM_RECV_S2_CLOSE_CONN;
			}

			//LMS_T2定时器到
			else if ((OpenChaoJi_os_get_ticks() - Msgcb->lm_recv_lms_t2_tick) >= Msgcb->lm_recv_lms_t2_intvl_ms)
			{
				//如果发送方  连续3次响应超时，发送LM_NACK,进入S2 , 否则发送LM_ACK(recv_no+1,k),重  置LMS T2,保持Sl
				Msgcb->lm_recv_err_cnt++;
				if (Msgcb->lm_recv_err_cnt >= 3)
				{
					gbt27930_b_rlm_sent_nack(Msgcb);
				}
				else
				{
					Msgcb->lm_recv_n = Msgcb->lm_recv_no + 1;
					Msgcb->lm_recv_k = Msgcb->lm_tfra - Msgcb->lm_recv_no;
					gbt27930_b_rlm_send_ack(Msgcb);
					Msgcb->lm_recv_lms_t2_tick = OpenChaoJi_os_get_ticks();
				}
			}

			//LMS_T3定时器到或主动中止传输
			else if (((OpenChaoJi_os_get_ticks() - Msgcb->lm_recv_lms_t3_tick) >= Msgcb->lm_recv_lms_t3_intvl_ms)
				|| (Msgcb->lm_recv_active_abort == 1))
			{
				//发送LM_NACK,进入S2
				gbt27930_b_rlm_sent_nack(Msgcb);
				Msgcb->lm_recv_state = LM_RECV_S2_CLOSE_CONN;
				Msgcb->lm_recv_active_abort = 0;
			}
			break;

		case LM_RECV_S2_CLOSE_CONN:
			//关闭LMS_T2、LMS_T3定时器(如开启),recv_no,err_cnt置零
			Msgcb->lm_recv_lms_t2_tick = 0;
			Msgcb->lm_recv_lms_t3_tick = 0;
			Msgcb->lm_recv_no = 0;
			Msgcb->lm_recv_err_cnt = 0;
			Msgcb->lm_recv_state = LM_RECV_S0_IDLE;
			break;

		default: break;
	}

	return 0;
}

/*
* @brief: 长消息接收发送ACK
* @param {OpenChaoJi_context_utility_transport} *context 系统上下文指针，包含必要的环境信息。
* @return {*}成功返回0，失败返回-1。
*/
int16_t gbt27930_b_rlm_send_ack(struct OpenChaoJi_gbt27930_b_rmcb * rmcb)
{
	struct can_pdu pdu;
    int16_t res;

	pdu.can_id.bit.sa = rmcb->src_addr;
	pdu.can_id.bit.ps = rmcb->dest_addr;

	pdu.can_id.bit.pf = PF_RMCF;
	pdu.can_id.bit.dp = 0;
	pdu.can_id.bit.edp = 0;
	pdu.can_id.bit.p = 3;
	pdu.can_id.bit.rsvd = 0;
	pdu.can_dlc = 8;

	pdu.data[0] = 1;
	pdu.data[1] = rmcb->lm_recv_n;	//待接收起始帧序号
	pdu.data[2] = rmcb->lm_recv_k;	//本次接收总帧数
	pdu.data[3] = 0xff;
	pdu.data[4] = 0xff;
	pdu.data[5] = 0xff;
	pdu.data[6] = 0xff;
	pdu.data[7] = 0xff;

	res = (*rmcb->can_output_func)(rmcb->param, &pdu);

	if (s_transport_debug_enable)
	{
		LOG_DATA_TRANSPORT("[%d]->b_rlm_ack[%08X][%d]", rmcb->tag, pdu.can_id.uint32_tWord, pdu.can_dlc);
		LOG_DATA_BUFF_TRANSPORT(pdu.data, pdu.can_dlc);
	}

	return res;
}

/*
* @brief: 长消息接收完成发送endofack
* @param {OpenChaoJi_context_utility_transport} *context 系统上下文指针，包含必要的环境信息。
* @return {*}成功返回0，失败返回-1。
*/
int16_t gbt27930_b_rlm_send_endofack(struct OpenChaoJi_gbt27930_b_rmcb * rmcb)
{
    int16_t res;
	struct can_pdu pdu;

	pdu.can_id.bit.sa = rmcb->src_addr;
	pdu.can_id.bit.ps = rmcb->dest_addr;

	pdu.can_id.bit.pf = PF_RMCF;
	pdu.can_id.bit.dp = 0;
	pdu.can_id.bit.edp = 0;
	pdu.can_id.bit.p = 3;
	pdu.can_id.bit.rsvd = 0;
	pdu.can_dlc = 8;

	pdu.data[0] = 3;
	pdu.data[1] = rmcb->lm_tfra;//发送总帧数
	pdu.data[2] = (rmcb->lm_recv_tbytes & 0x00ff);	//总字节数
	pdu.data[3] = ((rmcb->lm_recv_tbytes >> 8) & 0x00ff);//总字节数
	pdu.data[4] = 0xff;
	pdu.data[5] = 0xff;
	pdu.data[6] = 0xff;
	pdu.data[7] = 0xff;

	res = (*rmcb->can_output_func)(rmcb->param, &pdu);

	if (s_transport_debug_enable)
	{
		LOG_DATA_TRANSPORT("[%d]->b_rlm_end[%08X][%d]", rmcb->tag, pdu.can_id.uint32_tWord, pdu.can_dlc);
		LOG_DATA_BUFF_TRANSPORT(pdu.data, pdu.can_dlc);
	}

	return res;
}

/*
* @brief: 需要确认短消息ack函数
* @param {OpenChaoJi_context_utility_transport} *context 系统上下文指针，包含必要的环境信息。
* @return {*}成功返回0，失败返回-1。
*/
int16_t gbt27930_b_rsm_send_ack(struct OpenChaoJi_gbt27930_b_rmcb * rmcb)
{
    int16_t res;
	struct can_pdu pdu;

	pdu.can_id.bit.sa = rmcb->src_addr;
	pdu.can_id.bit.ps = rmcb->dest_addr;

	pdu.can_id.bit.pf = PF_RMCF;
	pdu.can_id.bit.dp = 0;
	pdu.can_id.bit.edp = 0;
	pdu.can_id.bit.p = 3;
	pdu.can_id.bit.rsvd = 0;
	pdu.can_dlc = 8;

	pdu.data[0] = 0;
	pdu.data[1] = 1;
	pdu.data[2] = 0xff;
	pdu.data[3] = 0xff;
	pdu.data[4] = 0xff;
	pdu.data[5] = 0xff;
	pdu.data[6] = 0xff;
	pdu.data[7] = 0xff;

	res = (*rmcb->can_output_func)(rmcb->param, &pdu);

	if (s_transport_debug_enable)
	{
		LOG_DATA_TRANSPORT("[%d]->b_rsm_ack[%08X][%d]", rmcb->tag, pdu.can_id.uint32_tWord, pdu.can_dlc);
		LOG_DATA_BUFF_TRANSPORT(pdu.data, pdu.can_dlc);
	}

	return res;
}

#endif
